/*--------------------------------------------------------------------
 * bgworker.h
 *		POSTGRES 可插拔后台工作接口
 *
 * 后台工作程序是一种能够运行任意用户提供代码的进程，
 * 包括正常事务。
 *
 * 任何通过 shared_preload_libraries 加载的外部模块都可以注册一个
 * 工作程序。工作程序也可以在运行时动态注册。在这两种情况下，
 * 工作程序进程都是从后端派生并运行用户提供的“main”函数。此代码可能连接到数据库并运行事务。
 * 工作程序可以无限期保持活动，但在发生关闭或崩溃时将被终止。
 *
 * 如果 postmaster 中的 fork() 调用失败，将稍后再试。注意
 * 失败只能是暂时的（由于高负载、内存压力、过多进程等导致的 fork 失败）；更永久性的问题，例如
 * 无法连接到数据库，在后端中会被后续检测到并通过让工作程序正常退出处理。返回代码为
 * 0 的工作程序将永远不会被重启，并将从工作程序列表中移除。返回代码为
 * 1 的工作程序将在配置的重启间隔后被重新启动（除非该间隔为 BGW_NEVER_RESTART）。
 * TerminateBackgroundWorker() 函数可用于终止动态注册的后台工作程序；将向工作程序发送 SIGTERM
 * 信号，并且在退出后不会被重启。每当后端知道
 * 工作程序不会被重启时，它会取消注册该工作程序，为新工作程序释放该工作程序的位置。
 *
 * 请注意，在一个数据库中可能同时存在多个工作程序，
 * 同一模块可能请求多个运行相同（或不同）代码的工作程序。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *		src/include/postmaster/bgworker.h
 *--------------------------------------------------------------------
 */
#ifndef BGWORKER_H
#define BGWORKER_H

/*---------------------------------------------------------------------
 * 外部模块 API。
 *---------------------------------------------------------------------
 */

/*
 * 传递此标志以使您的工作进程能够连接到共享内存。
 * 此标志是必需的。
 */
#define BGWORKER_SHMEM_ACCESS						0x0001

/*
 * 此标志表示 bgworker 需要一个数据库连接。连接
 * 不会自动建立；工作进程必须稍后自己建立。
 * 这要求也传递了 BGWORKER_SHMEM_ACCESS 标志。
 */
#define BGWORKER_BACKEND_DATABASE_CONNECTION		0x0002

/*
 * 此类在内部用于并行查询，以跟踪
 * 活跃并行工作进程的数量，并确保我们从未启动超过
 * max_parallel_workers 的并行工作进程。第三方
 * 背景工作进程不应使用此类。
 */
#define BGWORKER_CLASS_PARALLEL					0x0010
/* 在这里添加其他 bgworker 类 */


typedef void (*bgworker_main_type) (Datum main_arg);

/*
 * bgworker 可以请求启动的时间点
 */
typedef enum
{
	BgWorkerStart_PostmasterStart,
	BgWorkerStart_ConsistentState,
	BgWorkerStart_RecoveryFinished
} BgWorkerStartTime;

#define BGW_DEFAULT_RESTART_INTERVAL	60
#define BGW_NEVER_RESTART				-1
#define BGW_MAXLEN						96
#define BGW_EXTRALEN					128

typedef struct BackgroundWorker
{
	char		bgw_name[BGW_MAXLEN];
	char		bgw_type[BGW_MAXLEN];
	int			bgw_flags;
	BgWorkerStartTime bgw_start_time;
	int			bgw_restart_time;	/* 以秒为单位，或 BGW_NEVER_RESTART */
	char		bgw_library_name[BGW_MAXLEN];
	char		bgw_function_name[BGW_MAXLEN];
	Datum		bgw_main_arg;
	char		bgw_extra[BGW_EXTRALEN];
	pid_t		bgw_notify_pid; /* 在启动/停止时使用 SIGUSR1 此后端 */
} BackgroundWorker;

typedef enum BgwHandleStatus
{
	BGWH_STARTED,				/* 工作进程正在运行 */
	BGWH_NOT_YET_STARTED,		/* 工作进程尚未启动 */
	BGWH_STOPPED,				/* 工作进程已退出 */
	BGWH_POSTMASTER_DIED		/* postmaster 已死亡；工作进程状态不明确 */
} BgwHandleStatus;

struct BackgroundWorkerHandle;
typedef struct BackgroundWorkerHandle BackgroundWorkerHandle;

/* 在 shared_preload_libraries 中注册新的 bgworker */
extern void RegisterBackgroundWorker(BackgroundWorker *worker);

/* 从常规后端注册新的 bgworker */
extern bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
											BackgroundWorkerHandle **handle);

/* 查询 bgworker 的状态 */
extern BgwHandleStatus GetBackgroundWorkerPid(BackgroundWorkerHandle *handle,
											  pid_t *pidp);
extern BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pid);
extern BgwHandleStatus
			WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *);
extern const char *GetBackgroundWorkerTypeByPid(pid_t pid);

/* 终止 bgworker */
extern void TerminateBackgroundWorker(BackgroundWorkerHandle *handle);

/* 这在正在运行的工作进程中有效 */
extern PGDLLIMPORT BackgroundWorker *MyBgworkerEntry;

/*
 * 连接到指定的数据库，以指定的用户身份。 只有在注册时传递了 
 * BGWORKER_BACKEND_DATABASE_CONNECTION 的工作进程可以调用此函数。
 *
 * 如果用户名为 NULL，则使用启动超级用户。
 * 如果数据库名为 NULL，则连接到没有特定数据库的连接；
 * 只能访问共享目录。
 */
extern void BackgroundWorkerInitializeConnection(const char *dbname, const char *username, uint32 flags);

/* 与上述类似，但通过 OID 指定数据库和用户。 */
extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags);

/*
 * Flags to BackgroundWorkerInitializeConnection et al
 *
 *
 * 允许在连接到数据库时绕过 datallowconn 限制
 */
#define BGWORKER_BYPASS_ALLOWCONN 1


/* 阻塞/解除阻塞后台工作进程中的信号 */
extern void BackgroundWorkerBlockSignals(void);
extern void BackgroundWorkerUnblockSignals(void);

#endif							/* BGWORKER_H */
